package com.br.aiops.counter;

import com.br.aiops.rule.Rule;
import com.br.aiops.utils.Constants;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;

import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

public class CounterLadderValue {

    private static final Map<String, LadderValue> counterLadderValues = new ConcurrentHashMap<>();

    public static LadderValue getLadderValue(String counterKey) {
        return counterLadderValues.get(counterKey);
    }

    public static void setLadderValueIfAbsent(String counterKey, Rule rule) {
        counterLadderValues.putIfAbsent(counterKey, new LadderValue(rule));
    }

    public static void setLadderValue(String counterKey, LadderValue ladderValue) {
        counterLadderValues.put(counterKey, ladderValue);
    }

    /**
     * 升级阶梯参数
     */
    public static void upgradeTimes(String counterKey) {
        counterLadderValues.computeIfPresent(counterKey, (key, ladderValue) -> {
            ladderValue.upgradeTimes();
            return ladderValue;
        });
    }

    /**
     * 获取times
     * @param duration 持续时间
     * @return 获取times
     */
    public static Integer getTimesByDuration(String counterKey, int duration) {
        CounterLadderValue.LadderValue ladderValue = counterLadderValues.get(counterKey);
        if (Objects.nonNull(ladderValue)) {
            return ladderValue.getTimesByDuration(duration);
        }
        return 0;
    }

    /**
     * 删除对应的阶梯值
     * @param counterKey
     */
    public static void remove(String counterKey) {
        counterLadderValues.remove(counterKey);
    }


    @Data
    @Builder
    @AllArgsConstructor
    public static class LadderValue implements Serializable {

        //当前阶梯值
        private AtomicInteger currentTimes;

        private int level = 1;

        private Rule rule;

        public LadderValue(Rule rule) {
            this.rule = rule;
            //阶梯不为空，并且阶梯类型不是无阶梯时创建
            if (Objects.nonNull(rule.getLadderType()) && !Objects.equals(rule.getLadderType(), Constants.LADDER_TYPE_NONE)) {
                this.currentTimes = new AtomicInteger(getTimesStep().get(0));
            }
        }

        public void upgradeTimes() {
            //已达到最大值则使用最大值
            if (level < getTimesStep().size()) {
                level ++;
                this.currentTimes.addAndGet(getCurrentTimesStep());
            } else {
                this.currentTimes.addAndGet(getLastTimesStep());
            }
        }

        public Integer getTimesByDuration(int duration) {
            List<Integer> durStep = getDurStep();
            for (int i = 0; i < durStep.size(); i ++) {
                if (durStep.get(i) == duration) {
                    return getTimesStep().get(i);
                }
            }
            return 0;
        }

        private Integer getLastTimesStep() {
            return getTimesStep().get(getTimesStep().size() - 1);
        }

        public int getCurrentTimesStep() {
            return getTimesStep().get(level - 1);
        }

        /**
         * 获取持续时间阶梯数
         * @return 阶梯数
         */
        public final List<Integer> getDurStep() {
            //阶梯数按照乘以倍数后返回
            return fromString(rule.getDurStep(), ",").stream().map(step -> step * rule.getDuration()).collect(Collectors.toList());
        }

        /**
         * 获取告警次数阶梯
         * @return 阶梯数
         */
        public final List<Integer> getTimesStep() {
            return fromString(rule.getTimesStep(), ",");
        }

        private final List<Integer> fromString(String str, String split) {
            if (StringUtils.isBlank(str)) {
                return Lists.newArrayList(-1);
            } else if (!str.contains(",")) {
                return Lists.newArrayList(Integer.valueOf(str));
            }
            return Arrays.stream(str.split(split)).map(Integer::valueOf).collect(Collectors.toList());
        }
    }
}
